import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_cancellable_tile_provider/flutter_map_cancellable_tile_provider.dart';
import 'package:intl/intl.dart';
import 'package:macless_haystack/history/gpx_helper.dart';
import 'package:macless_haystack/location/location_model.dart';
import 'package:logger/logger.dart';
import 'package:macless_haystack/accessory/accessory_model.dart';
import 'package:latlong2/latlong.dart';
import 'package:macless_haystack/history/days_selection_slider.dart';
import 'package:macless_haystack/history/location_popup.dart';

import 'dart:math';

import 'package:macless_haystack/map/CustomTileProvider.dart';

class AccessoryHistory extends StatefulWidget {
  final Accessory accessory;

  /// Shows previous locations of a specific [accessory] on a map.
  /// The locations are connected by a chronological line.
  /// The number of days to go back can be adjusted with a slider.
  const AccessoryHistory({
    super.key,
    required this.accessory,
  });

  @override
  State<StatefulWidget> createState() {
    return _AccessoryHistoryState();
  }
}

class _AccessoryHistoryState extends State<AccessoryHistory> {
  LocationModel locationModel = LocationModel();

  double _currentZoom = 13.0;
  DateTime? _lastZoomUpdate;
  late MapController _mapController;

  bool showPopup = false;
  Pair<dynamic, dynamic>? popupEntry;

  //int numberOfDays = 7;
  RangeValues dayRange = RangeValues(
    1,
    1,
  );
  bool isLineLayerVisible = true;
  bool isPointLayerVisible = true;
  bool isArrowLayerVisible = true;

  @override
  void initState() {
    super.initState();
    _mapController = MapController();
    _mapController.mapEventStream.listen((event) {
      if ((event is MapEventMove || event is MapEventScrollWheelZoom) &&
          _isUserGesture()) {
        _handleZoomChange();
      }
    });

    DateTime latest = widget.accessory.latestHistoryEntry();
    //numberOfDays =
    //  min(DateTime.now().difference(latest).inDays + 1, numberOfDays);
    var days = min(DateTime.now().difference(latest).inDays + 1, 7);
    dayRange = RangeValues(
      1,
      days.toDouble(),
    );
  }

  bool _isUserGesture() {
    // 简单的防抖处理，确保不是太频繁的更新
    final now = DateTime.now();
    if (_lastZoomUpdate != null &&
        now.difference(_lastZoomUpdate!) < Duration(milliseconds: 200)) {
      return false;
    }
    _lastZoomUpdate = now;
    return true;
  }

  void _handleZoomChange() {
    final newZoom = _mapController.camera.zoom;
    if (newZoom != _currentZoom) {
      setState(() {
        _currentZoom = newZoom;
      });
    }
  }

  double _calculateBearing(LatLng start, LatLng end) {
    final lat1 = start.latitude * pi / 180;
    final lon1 = start.longitude * pi / 180;
    final lat2 = end.latitude * pi / 180;
    final lon2 = end.longitude * pi / 180;

    final y = sin(lon2 - lon1) * cos(lat2);
    final x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1);
    final bearing = atan2(y, x) * 180 / pi;
    return (bearing + 360) % 360;
  }

  List<Marker> _createArrowMarkers(List<LatLng> points, double zoom) {
    final arrows = <Marker>[];
    const arrowSize = 15.0;

    // 动态调整间距 - 基于zoom级别
    // zoom越大（地图越放大），箭头越密集
    final double baseSpacing = 450.0; // 在zoom=13时的基准间距
    final spacing = _calculateDynamicSpacing(zoom, baseSpacing);

    final distance = Distance();

    for (int i = 0; i < points.length - 1; i++) {
      final start = points[i];
      final end = points[i + 1];
      final segmentDistance = distance(start, end);
      final segments = (segmentDistance / spacing).floor();

      if (segments < 1) continue;

      final latStep = (end.latitude - start.latitude) / segments;
      final lngStep = (end.longitude - start.longitude) / segments;

      for (int j = 0; j < segments; j++) {
        final ratio = j / segments;
        final point = LatLng(
          start.latitude + latStep * j,
          start.longitude + lngStep * j,
        );

        final angle = _calculateBearing(
          j == 0
              ? start
              : LatLng(
                  start.latitude + latStep * (j - 1),
                  start.longitude + lngStep * (j - 1),
                ),
          point,
        );

        arrows.add(
          Marker(
            point: point,
            width: arrowSize,
            height: arrowSize,
            child: Transform.rotate(
              angle: angle * (pi / 180),
              child: Icon(
                Icons.keyboard_double_arrow_up,
                color: Colors.white,
                size: arrowSize,
                shadows: [
                  Shadow(
                    color: Colors.black, // 描边颜色
                    blurRadius: 0,
                    offset: Offset(1, 0),
                  ),
                  Shadow(
                    color: Colors.black,
                    blurRadius: 0,
                    offset: Offset(-1, 0),
                  ),
                  Shadow(
                    color: Colors.black,
                    blurRadius: 0,
                    offset: Offset(0, 1),
                  ),
                  Shadow(
                    color: Colors.black,
                    blurRadius: 0,
                    offset: Offset(0, -1),
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }

    return arrows;
  }

  double _calculateDynamicSpacing(double zoom, double baseSpacing) {
    // 非线性调整公式，可根据需要修改
    // zoom越大（地图越放大），间距越小
    final exponent = (13 - zoom).clamp(-6, 11).toDouble(); // 限制变化范围
    return baseSpacing * pow(2, exponent); // 使用1.8作为基数，变化更平缓
  }

  @override
  Widget build(BuildContext context) {
    List<Pair<dynamic, dynamic>> filteredEntries = filterHistoryEntries();
    var historyLength = filteredEntries.length;
    List<Polyline> polylines = [];
    List<LatLng> routerPoints = [];
    List<Marker> arrowMarkers = [];

    if (historyLength > 255) {
      historyLength = 255;
    }
    int delta = (255 ~/ max(1, (historyLength - 1))).ceil();
    var blue = delta;

    for (int i = 0; i < filteredEntries.length - 1; i++) {
      var entry = filteredEntries[i];
      var nextEntry = filteredEntries[i + 1];
      List<LatLng> points = [];
      var point = locationModel.wgs84ToGcj02(entry.location)!;
      var nextPoint = locationModel.wgs84ToGcj02(nextEntry.location)!;
      points.add(point);
      points.add(nextPoint);
      routerPoints.add(point);
      if (i == filteredEntries.length - 2) {
        routerPoints.add(nextPoint);
      }

      if (isLineLayerVisible) {
        polylines.add(Polyline(
          points: points,
          strokeWidth: 4,
          color: Color.fromRGBO(33, 150, blue, 1),
        ));
      }
      blue += min(delta.toInt(), 255);
    }

    if (isArrowLayerVisible) {
      arrowMarkers = _createArrowMarkers(routerPoints, _currentZoom);
    }

    // Filter for the locations after the specified cutoff date (now - number of days)
    var visibility = [
      isLineLayerVisible,
      isPointLayerVisible,
      isArrowLayerVisible
    ];
    return Scaffold(
      appBar: AppBar(
        title: FittedBox(
            fit: BoxFit.scaleDown,
            child: Text(
              "${widget.accessory.name} (${filteredEntries.length} 条历史位置)",
            )),
      ),
      body: SafeArea(
        child: Column(
          children: <Widget>[
            Flexible(
              flex: 12,
              fit: FlexFit.tight,
              child: FlutterMap(
                key: ValueKey(MediaQuery.of(context).orientation),
                mapController: _mapController,
                options: MapOptions(
                  backgroundColor: Theme.of(context).colorScheme.surface,
                  initialCenter: const LatLng(51.1657, 10.4515),
                  maxZoom: 19.0,
                  minZoom: 2.0,
                  initialZoom: _currentZoom,
                  onMapReady: mapReadyInit,
                  interactionOptions: const InteractionOptions(
                      enableMultiFingerGestureRace: true,
                      flags: InteractiveFlag.pinchZoom |
                          InteractiveFlag.drag |
                          InteractiveFlag.doubleTapZoom |
                          InteractiveFlag.scrollWheelZoom |
                          InteractiveFlag.flingAnimation |
                          InteractiveFlag.pinchMove |
                          InteractiveFlag.pinchZoom),
                  onTap: (_, __) {
                    setState(() {
                      showPopup = false;
                      popupEntry = null;
                    });
                  },
                ),
                children: [
                  TileLayer(
                      tileProvider:
                          CustomTileProvider(), // CancellableNetworkTileProvider(),
                      urlTemplate:
                          "https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
                      tileBuilder: (context, child, tile) {
                        var isDark =
                            (Theme.of(context).brightness == Brightness.dark);
                        return isDark
                            ? ColorFiltered(
                                colorFilter: const ColorFilter.matrix([
                                  -1,
                                  0,
                                  0,
                                  0,
                                  255,
                                  0,
                                  -1,
                                  0,
                                  0,
                                  255,
                                  0,
                                  0,
                                  -1,
                                  0,
                                  255,
                                  0,
                                  0,
                                  0,
                                  1,
                                  0,
                                ]),
                                child: child,
                              )
                            : child;
                      }),
                  // The line connecting the locations chronologically
                  PolylineLayer(
                    polylines: polylines,
                  ),
                  MarkerLayer(
                    markers: arrowMarkers,
                  ),
                  // The markers for the historic locations
                  MarkerLayer(
                    markers: filteredEntries
                        .map((entry) => Marker(
                              point:
                                  locationModel.wgs84ToGcj02(entry.location)!,
                              child: GestureDetector(
                                onTap: () {
                                  setState(() {
                                    showPopup = true;
                                    popupEntry = entry;
                                  });
                                },
                                child: Icon(
                                  Icons.circle,
                                  size: isPointLayerVisible
                                      ? calculateSize(entry)
                                      : 0,
                                  color: entry == popupEntry
                                      ? Colors.red
                                      : Colors
                                          .black, //.of(context).indicatorColor,
                                ),
                              ),
                            ))
                        .toList(),
                  ),
                  // Displays the tooltip if active
                  MarkerLayer(
                    markers: [
                      if (showPopup)
                        LocationPopup(
                            location: locationModel
                                .wgs84ToGcj02(popupEntry!.location)!,
                            time: popupEntry!.start,
                            end: popupEntry!.end,
                            ctx: context),
                    ],
                  ),
                  ToggleButtons(
                    isSelected: visibility,
                    onPressed: (int index) {
                      setState(() {
                        visibility[index] = !visibility[index];
                        isLineLayerVisible = visibility[0];
                        isPointLayerVisible = visibility[1];
                        isArrowLayerVisible = visibility[2];
                        showPopup = false;
                        popupEntry = null;
                      });
                    },
                    children: [
                      Icon(Icons.timeline),
                      Icon(Icons.scatter_plot_rounded),
                      Icon(Icons.keyboard_double_arrow_up),
                    ],
                  )
                ],
              ),
            ),
            const Center(
              child: Text(
                '轨迹线越绿则时间越早，越蓝则越接近当前时刻',
                style: TextStyle(fontSize: 13, color: Colors.grey),
              ),
            ),
            Flexible(
              flex: 3,
              fit: FlexFit.tight,
              child: DaysSelectionSlider(
                // numberOfDays: numberOfDays.toDouble(),
                selectedRange: dayRange,
                /* onChanged: (double newValue) {
                  setState(() {
                    showPopup = false;
                    popupEntry = null;
                    numberOfDays = newValue.toInt();
                    WidgetsBinding.instance.addPostFrameCallback((_) {
                      mapReady();
                    });
                  });
                }, */
                onChanged: (RangeValues newRange) {
                  setState(() {
                    showPopup = false;
                    popupEntry = null;
                    dayRange = newRange;
                    WidgetsBinding.instance.addPostFrameCallback((_) {
                      mapReady();
                    });
                  });
                },
              ),
            ),
            Center(
              child: Padding(
                padding: const EdgeInsets.all(20),
                child: ElevatedButton(
                  child: const Text("导出GPX"),
                  onPressed: () async {
                    var now = DateTime.now();
                    var today = DateTime(now.year, now.month, now.day);
                    var end = today
                        .subtract(Duration(days: (dayRange.start - 1).round()));
                    var days = dayRange.end - dayRange.start + 1;
                    var start =
                        end.subtract(Duration(days: (days.round() + 1)));

                    await GPXHelper.export(
                        "${widget.accessory.name} 轨迹 ${DateFormat('MM-dd').format(start)}~${DateFormat('MM-dd').format(end)}.gpx",
                        filteredEntries);
                  },
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  double calculateSize(Pair<dynamic, dynamic> entry) {
    //Point gets larger every 6 hours
    var d = (entry.end.difference(entry.start).inHours / 6).floor() + 1;
    return min(d * 10, 40); // 4 steps is enough
  }

  mapReady() {
    List<Pair<dynamic, dynamic>> filteredEntries = filterHistoryEntries();
    if (filteredEntries.isNotEmpty) {
      var historicLocations = filteredEntries
          .map((entry) => locationModel.wgs84ToGcj02(entry.location)!)
          .toList();
      var bounds = LatLngBounds.fromPoints(historicLocations);
      _mapController.fitCamera(CameraFit.bounds(bounds: bounds));
    }
  }

  mapReadyInit() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      mapReady();
    });
  }

  List<Pair<dynamic, dynamic>> filterHistoryEntries() {
    var now = DateTime.now();
    /* var filteredEntries = widget.accessory
        .getSortedLocationHistory()
        .where(
          (element) => element.end.isAfter(
            now.subtract(Duration(days: numberOfDays.round())),
          ),
        )
        .toList(); */
    var today = DateTime(now.year, now.month, now.day);
    var end = today.subtract(Duration(days: (dayRange.start - 2).round()));

    var days = dayRange.end - dayRange.start + 1;
    var filteredEntries = widget.accessory
        .getSortedLocationHistory()
        .where(
          (element) =>
              element.end.isAfter(
                end.subtract(Duration(days: days.round())),
              ) &&
              element.start.isBefore(end),
        )
        .toList();
    return filteredEntries;
  }

  var logger = Logger(
    printer: PrettyPrinter(methodCount: 0),
  );
}
